using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Web.Services.Protocols;

namespace Alex.Library.Cloud.VMWare.V51.Util
{
    public enum LogLevel
    {
        Information = 0,
        Warning = 1,
        Error = 2,
        Fault = 3
    }

    public interface ILog
    {
        void WriteLine(LogLevel level, string msgformat, params string[] args);
    }

    public sealed class LogManager
    {
        public LogManager()
        {

        }

        private Dictionary<string, ILog> _logList = new Dictionary<string, ILog>();

        public void RegisterLog(string logName, ILog log)
        {
            lock (_logList)
            {
                _logList[logName] = log;
            }
        }

        public ILog UnRegisterLog(string logName)
        {
            lock (_logList)
            {
                if (_logList.ContainsKey(logName))
                {
                    ILog log = _logList[logName];
                    _logList.Remove(logName);
                    return log;
                }
                return null;
            }
        }

        private void WriteLine(LogLevel level, string msgformat, params string[] args)
        {
            lock (_logList)
            {
                if (_logList.Count > 0)
                {
                    foreach (ILog log in _logList.Values)
                    {
                        log.WriteLine(level, msgformat, args);
                    }
                }
            }
        }

        public void Information(string msgformat, params string[] args)
        {
            WriteLine(LogLevel.Information, msgformat, args);
        }

        public void Warning(string msgformat, params string[] args)
        {
            WriteLine(LogLevel.Warning, msgformat, args);
        }

        public void Error(string msgformat, params string[] args)
        {
            WriteLine(LogLevel.Error, msgformat, args);
        }

        public void Fault(string msgformat, params string[] args)
        {
            WriteLine(LogLevel.Fault, msgformat, args);
        }

        public void Exception(Exception e)
        {
            if (e is SoapException)
            {
                SoapException se = (SoapException)e;
                Error("Caught SoapException: Actor:{0}, Code:{1}, Detail XML:{2}",
                    se.Actor, se.Code.ToString(), se.Detail.OuterXml);
            }
            else
            {
                Error("Caught Exception: Name:{0}, Message:{1}, Trace:{2}",
                    e.GetType().Name, e.Message, e.StackTrace);
            }
        }
    }

    /// <summary>
    /// Log to file.
    /// </summary>
    public class FileLog : ILog
    {
        public FileLog(string filePath)
        {
            this.FilePath = filePath;
        }

        public string FilePath { get; set; }
        
        public void WriteLine(LogLevel level, string msgformat, params string[] args)
        {
            lock (this)
            {
                string msg = String.Format(msgformat, args);
                msg = String.Format("[{0}--{1:yyyy-MM-dd HH:mm:ss}] {2}", level.ToString(), DateTime.Now, msg);
                File.AppendAllText(FilePath, msg);
            }
        }
    }

    /// <summary>
    /// Log to console.
    /// </summary>
    public class ConsoleLog : ILog
    {
        public ConsoleLog()
        {

        }

        public void WriteLine(LogLevel level, string msgformat, params string[] args)
        {            
            Console.BackgroundColor = ConsoleColor.Black;
            switch (level)
            {
                case LogLevel.Information:                    
                    Console.ForegroundColor = ConsoleColor.White;                    
                    break;
                case LogLevel.Warning:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    break;
                case LogLevel.Error:
                    Console.ForegroundColor = ConsoleColor.Red;
                    break;
                case LogLevel.Fault:
                    Console.ForegroundColor = ConsoleColor.DarkRed;
                    break;
            }
            string msg = String.Format(msgformat, args);
            Console.WriteLine("[{0}--{1:yyyy-MM-dd HH:mm:ss}] {2}", level.ToString(), DateTime.Now, msg);
        }
    }

    /// <summary>
    /// Log to trace console.
    /// </summary>
    public class TraceLog : ILog
    {
        public void WriteLine(LogLevel level, string msgformat, params string[] args)
        {
            string msg = String.Format(msgformat, args);
            switch (level)
            {
                case LogLevel.Information:
                    System.Diagnostics.Trace.TraceInformation("[{0}--{1:yyyy-MM-dd HH:mm:ss}] {2}", level.ToString(), DateTime.Now, msg);
                    break;
                case LogLevel.Warning:
                    System.Diagnostics.Trace.TraceWarning("[{0}--{1:yyyy-MM-dd HH:mm:ss}] {2}", level.ToString(), DateTime.Now, msg);
                    break;
                case LogLevel.Error:
                case LogLevel.Fault:
                    System.Diagnostics.Trace.TraceError("[{0}--{1:yyyy-MM-dd HH:mm:ss}] {2}", level.ToString(), DateTime.Now, msg);
                    break;
            }
            
        }
    }
}
